unit uModelParameters;

interface

uses
  System.SysUtils,
  Vcl.Graphics;

type
  TLeafShape = byte;

  TModelParameters = class
  private
    FShape: byte;
    FBaseSize: real;
    FBaseSplits: byte;
    FScale, FScaleV: real;
    FZScale, FZScaleV: real;
    FLeveled: byte;
    FRatio, FRatioPower: real;
    FLobes: byte;
    FLobeDepth: real;
    FFlare: real;
    FLeaves: integer;
    FLeafShape: TLeafShape; // byte
    FLeafScale, FLeafScaleX: real;
    FLeafQuality: real;
    // LeafQuality determine # of Leaves *LeafQuality and Size  SQRT(LeafQuality)
    FLeafColor: TColor;
    FLeafColorVariation: boolean;
    FLeafBackColor: TColor;
    FLeafBackColorVariation: boolean;
    FAttractionUp: real;
    FPruneRatio: real;
    FPruneWidth, FPruneWidthPeak: real;
    FPrunePowerLow, FPrunePowerHigh: real;
    FScale0, FScaleV0: real;
    FnDownAngle, FnDownAngleV: array of real;
    FnRotate, FnRotateV: array of real;
    FnLength, FnLengthV: array of real;
    FnTaper: array of real;
    FnBranches: array of integer;
    FnSegSplits: array of real;
    FnSplitAngle, FnSplitAngleV: array of real;
    FnCurveRes: array of integer;
    FnCurve, FnCurveBack, FnCurveV: array of real;
    FnVertices: array of integer;
    // New added stuff
    FTreeSeed: integer;
    FHealth: byte; // Not used at all yet
    FSeason: byte;
    FTreeImageFile: String;
    FTreeShapeFile: String;
    FTreeBarkFile: String;
    FTreeColorVariation: boolean;
    FTreeColor: TColor; // Dunno how to set
    FDistance: real; // Link to Leaf Quality ?
    FWindStrength: byte; // 0..30 ?
    FWindGust: byte; // 0..?
    FWindFrom: integer; // 0..360
    FSunHeight: byte; // 0..90
    FSunStrength: byte; // 0..100
    FSunFrom: integer; // 0..360
    FnLeaves: array of integer;
    FLeafImageFile: String;
    FLeafShapeFile: String;
    FLeafTextureFile: String;
    FLeafLocation: byte; // Range Box selection
    FFLeafsPer: integer; { Set }
    FLeafGrouping: byte; { Range Box selection }

    FFruitPattern: byte; { Range Box selection }
    FFruitScale, FFruitScaleX: real;
    FFruits: integer; { ~ Leaves.. }
    FFruitPer: integer; { # }
    FFruitLocation: byte; { Range Box selection }
    FFruitImageFile: String;
    FFruitShapeFile: String;
    FFruitTextureFile: String;
    FFruitColorVariation: boolean;
    FFruitColor: TColor;

    function GetnDownAngle(Index: byte): real;
    function GetnDownAngleV(Index: byte): real;
    function GetnRotate(Index: byte): real;
    function GetnRotateV(Index: byte): real;
    function GetnLength(Index: byte): real;
    function GetnLengthV(Index: byte): real;
    function GetnTaper(Index: byte): real;
    function GetnBranches(Index: byte): integer;
    function GetnSegSplits(Index: byte): real;
    function GetnSplitAngle(Index: byte): real;
    function GetnSplitAngleV(Index: byte): real;
    function GetnCurveRes(Index: byte): integer;
    function GetnCurve(Index: byte): real;
    function GetnCurveV(Index: byte): real;
    function GetnCurveBack(Index: byte): real;
    function GetnVertices(Index: byte): integer;
    function GetnLeaves(Index: byte): integer;
    procedure SetnDownAngle(Index: byte; Value: real);
    procedure SetnDownAngleV(Index: byte; Value: real);
    procedure SetnRotate(Index: byte; Value: real);
    procedure SetnRotateV(Index: byte; Value: real);
    procedure SetnLength(Index: byte; Value: real);
    procedure SetnLengthV(Index: byte; Value: real);
    procedure SetnTaper(Index: byte; Value: real);
    procedure SetnBranches(Index: byte; Value: integer);
    procedure SetnSegSplits(Index: byte; Value: real);
    procedure SetnSplitAngle(Index: byte; Value: real);
    procedure SetnSplitAngleV(Index: byte; Value: real);
    procedure SetnCurveRes(Index: byte; Value: integer);
    procedure SetnCurve(Index: byte; Value: real);
    procedure SetnCurveV(Index: byte; Value: real);
    procedure SetnCurveBack(Index: byte; Value: real);
    procedure SetnVertices(Index: byte; Value: integer);
    procedure SetnLeaves(Index: byte; Value: integer);
  public
    // Model parameters
    property Shape: byte read FShape write FShape;
    property BaseSize: real read FBaseSize write FBaseSize;
    property BaseSplits: byte read FBaseSplits write FBaseSplits;
    property Scale: real read FScale write FScale;
    property ScaleV: real read FScaleV write FScaleV;
    property ZScale: real read FZScale write FZScale;
    property ZScaleV: real read FZScaleV write FZScaleV;
    property Levelers: byte read FLeveled write FLeveled;
    property Ratio: real read FRatio write FRatio;
    property RatioPower: real read FRatioPower write FRatioPower;
    property Lobes: byte read FLobes write FLobes;
    property LobeDepth: real read FLobeDepth write FLobeDepth;
    property Flare: real read FFlare write FFlare;
    property Leaves: integer read FLeaves write FLeaves;
    property LeafShape: TLeafShape read FLeafShape write FLeafShape;
    property LeafScale: real read FLeafScale write FLeafScale;
    property LeafScaleX: real read FLeafScaleX write FLeafScaleX;
    property LeafQuality: real read FLeafQuality write FLeafQuality;
    property LeafColor: TColor read FLeafColor write FLeafColor;
    property LeafColorVariation: boolean read FLeafColorVariation
      write FLeafColorVariation;
    property LeafBackColor: TColor read FLeafBackColor write FLeafBackColor;
    property LeafBackColorVariation: boolean read FLeafBackColorVariation
      write FLeafBackColorVariation;
    property AttractionUp: real read FAttractionUp write FAttractionUp;
    property PruneRatio: real read FPruneRatio write FPruneRatio;
    property PruneWidth: real read FPruneWidth write FPruneWidth;
    property PruneWidthPeak: real read FPruneWidthPeak write FPruneWidthPeak;
    property PrunePowerLow: real read FPrunePowerLow write FPrunePowerLow;
    property PrunePowerHigh: real read FPrunePowerHigh write FPrunePowerHigh;
    property Scale0: real read FScale0 write FScale0;
    property ScaleV0: real read FScaleV0 write FScaleV0;
    property nDownAngle[Index: byte]: real read GetnDownAngle
      write SetnDownAngle;
    property nDownAngleV[Index: byte]: real read GetnDownAngleV
      write SetnDownAngleV;
    property nRotate[Index: byte]: real read GetnRotate write SetnRotate;
    property nRotateV[Index: byte]: real read GetnRotateV write SetnRotateV;
    property nLength[Index: byte]: real read GetnLength write SetnLength;
    property nLengthV[Index: byte]: real read GetnLengthV write SetnLengthV;
    property nTaper[Index: byte]: real read GetnTaper write SetnTaper;
    property nBranches[Index: byte]: integer read GetnBranches
      write SetnBranches;
    property nSegSplits[Index: byte]: real read GetnSegSplits
      write SetnSegSplits;
    property nSplitAngle[Index: byte]: real read GetnSplitAngle
      write SetnSplitAngle;
    property nSplitAngleV[Index: byte]: real read GetnSplitAngleV
      write SetnSplitAngleV;
    property nCurveRes[Index: byte]: integer read GetnCurveRes
      write SetnCurveRes;
    property nCurve[Index: byte]: real read GetnCurve write SetnCurve;
    property nCurveBack[Index: byte]: real read GetnCurveBack
      write SetnCurveBack;
    property nCurveV[Index: byte]: real read GetnCurveV write SetnCurveV;
    property nVertices[Index: byte]: integer read GetnVertices
      write SetnVertices;
    { New added stuff }
    property TreeSeed: integer read FTreeSeed write FTreeSeed;
    property Health: byte read FHealth write FHealth;
    property Season: byte read FSeason write FSeason;
    property TreeImageFile: String read FTreeImageFile write FTreeImageFile;
    property TreeShapeFile: String read FTreeShapeFile write FTreeShapeFile;
    property TreeBarkFile: String read FTreeBarkFile write FTreeBarkFile;
    property TreeColorVariation: boolean read FTreeColorVariation
      write FTreeColorVariation;
    property TreeColor: TColor read FTreeColor write FTreeColor;
    property Distance: real read FDistance write FDistance;
    property WindStrength: byte read FWindStrength write FWindStrength;
    property WindGust: byte read FWindGust write FWindGust;
    property WindFrom: integer read FWindFrom write FWindFrom;
    property SunHeight: byte read FSunHeight write FSunHeight;
    property SunStrength: byte read FSunStrength write FSunStrength;
    property SunFrom: integer read FSunFrom write FSunFrom;
    // Added so there can be Leaves on every stem
    property nLeaves[Index: byte]: integer read GetnLeaves write SetnLeaves;
    property LeafImageFile: String read FLeafImageFile write FLeafImageFile;
    property LeafShapeFile: String read FLeafShapeFile write FLeafShapeFile;
    property LeafTextureFile: String read FLeafTextureFile
      write FLeafTextureFile;
    property LeafLocation: byte read FLeafLocation write FLeafLocation;
    property FLeafsPer: integer read FFLeafsPer write FFLeafsPer;
    property LeafGrouping: byte read FLeafGrouping write FLeafGrouping;
    property FruitPattern: byte read FFruitPattern write FFruitPattern;
    property FruitScale: real read FFruitScale write FFruitScale;
    property FruitScaleX: real read FFruitScaleX write FFruitScaleX;
    property Fruits: integer read FFruits write FFruits;
    property FruitPer: integer read FFruitPer write FFruitPer;
    property FruitLocation: byte read FFruitLocation write FFruitLocation;
    property FruitImageFile: String read FFruitImageFile write FFruitImageFile;
    property FruitShapeFile: String read FFruitShapeFile write FFruitShapeFile;
    property FruitTextureFile: String read FFruitTextureFile
      write FFruitTextureFile;
    property FruitColorVariation: boolean read FFruitColorVariation
      write FFruitColorVariation;
    property FruitColor: TColor read FFruitColor write FFruitColor;
  public
    constructor Create; overload;
    { Pre: True
      Post: A TModelParameters class has been created. None of the properties
      have been initialized. }
    constructor Create(Levels: byte); overload;
    { Pre: True
      Post: A TModelParameters class has been created. All the dynamic arrays
      have been created and set to the appropiate length (ALevels + 1). }
    destructor Destroy; override;

    function Clones: TModelParameters;
    { Pre: True
      Ret: An exact copy of itself }
  end;

implementation

constructor TModelParameters.Create;
{ Pre: True
  Post: A TModelParameters class has been created. None of the properties
  have been initialized. }
begin
  inherited Create;
end;

constructor TModelParameters.Create(Levels: byte);
{ Pre: True
  Post: A TModelParameters class has been created. All the dynamic arrays
  have been created and set to the appropiate length (ALevels + 1). }
begin
  inherited Create;

  FLeveled := Levels;

  { The array length of the Stem parameters is equal to ALevels. So, the total
    length of the stem parameter arrays is Levels - 1, because the last level
    of recursion is reserved for the leaves. }

  SetLength(FnDownAngle, Levels);
  SetLength(FnDownAngleV, Levels);
  SetLength(FnRotate, Levels);
  SetLength(FnRotateV, Levels);
  SetLength(FnLength, Levels);
  SetLength(FnLengthV, Levels);
  SetLength(FnTaper, Levels);
  SetLength(FnBranches, Levels);
  SetLength(FnSegSplits, Levels);
  SetLength(FnSplitAngle, Levels);
  SetLength(FnSplitAngleV, Levels);
  SetLength(FnCurveRes, Levels);
  SetLength(FnCurve, Levels);
  SetLength(FnCurveBack, Levels);
  SetLength(FnCurveV, Levels);
  SetLength(FnVertices, Levels);
  SetLength(FnLeaves, Levels); { added }
end;

destructor TModelParameters.Destroy;
begin
  Finalize(FnDownAngle);
  Finalize(FnDownAngleV);
  Finalize(FnRotate);
  Finalize(FnRotateV);
  Finalize(FnLength);
  Finalize(FnTaper);
  Finalize(FnBranches);
  Finalize(FnSegSplits);
  Finalize(FnSplitAngle);
  Finalize(FnSplitAngleV);
  Finalize(FnCurveRes);
  Finalize(FnCurveBack);
  Finalize(FnCurve);
  Finalize(FnCurveV);
  Finalize(FnVertices);
  Finalize(FnLeaves);
  inherited Destroy;
end;

function TModelParameters.GetnBranches(Index: byte): integer;
{ Pre: 0 <= Index < Length(FnBranches)
  Ret: FnBranches[Index] }
begin
  Result := FnBranches[Index];
end;

function TModelParameters.GetnCurve(Index: byte): real;
{ Pre: 0 <= Index < Length(FnCurve)
  Ret: FnCurve[Index] }
begin
  Result := FnCurve[Index];
end;

function TModelParameters.GetnCurveBack(Index: byte): real;
{ Pre: 0 <= Index < Length(FnCurveBack)
  Ret: FnCurveBack[Index] }
begin
  Result := FnCurveBack[Index];
end;

function TModelParameters.GetnCurveRes(Index: byte): integer;
{ Pre: 0 <= Index < Length(FnCurveRes)
  Ret: FnCurveRes[Index] }
begin
  Result := FnCurveRes[Index];
end;

function TModelParameters.GetnCurveV(Index: byte): real;
{ Pre: 0 <= Index < Length(FnCurveV)
  Ret: FnCurveV[Index] }
begin
  Result := FnCurveV[Index];
end;

function TModelParameters.GetnDownAngle(Index: byte): real;
{ Pre: 0 <= Index < Length(FnDownAngle)
  Ret: FnDownAngle[Index] }
begin
  Result := FnDownAngle[Index];
end;

function TModelParameters.GetnDownAngleV(Index: byte): real;
{ Pre: 0 <= Index < Length(FnDownAngleV)
  Ret: FnDownAngleV[Index] }
begin
  Result := FnDownAngleV[Index];
end;

function TModelParameters.GetnLength(Index: byte): real;
{ Pre: 0 <= Index < Length(FnLength)
  Ret: FnLength[Index] }
begin
  Result := FnLength[Index];
end;

function TModelParameters.GetnLengthV(Index: byte): real;
{ Pre: 0 <= Index < Length(FnLengthV)
  Ret: FnLengthV[Index] }
begin
  Result := FnLengthV[Index];
end;

function TModelParameters.GetnRotate(Index: byte): real;
{ Pre: 0 <= Index < Length(FnRotate)
  Ret: FnRotate[Index] }
begin
  Result := FnRotate[Index];
end;

function TModelParameters.GetnRotateV(Index: byte): real;
{ Pre: 0 <= Index < Length(FnRotateV)
  Ret: FnRotateV[Index] }
begin
  Result := FnRotateV[Index];
end;

function TModelParameters.GetnSegSplits(Index: byte): real;
{ Pre: 0 <= Index < Length(FnSegSplits)
  Ret: FnSegSplits[Index] }
begin
  Result := FnSegSplits[Index];
end;

function TModelParameters.GetnSplitAngle(Index: byte): real;
{ Pre: 0 <= Index < Length(FnSplitAngle)
  Ret: FnSplitAngle[Index] }
begin
  Result := FnSplitAngle[Index];
end;

function TModelParameters.GetnSplitAngleV(Index: byte): real;
{ Pre: 0 <= Index < Length(FnSplitAngleV)
  Ret: FnSplitAngleV[Index] }
begin
  Result := FnSplitAngleV[Index];
end;

function TModelParameters.GetnTaper(Index: byte): real;
{ Pre: 0 <= Index < Length(FnTaper)
  Ret: FnTaper[Index] }
begin
  Result := FnTaper[Index];
end;

function TModelParameters.GetnVertices(Index: byte): integer;
{ Pre: 0 <= Index < Length(FnVertices)
  Ret: FnVertices[Index] }
begin
  Result := FnVertices[Index];
end;

function TModelParameters.GetnLeaves(Index: byte): integer;
{ Pre: 0 <= Index < Length(FnLeaves)
  Ret: FnLeaves[Index] }
begin
  Result := FnLeaves[Index];
end;

procedure TModelParameters.SetnLeaves(Index: byte; Value: integer);
{ Pre: 0 <= Index < Length(FnLeaves)
  Post: FnLeavess[Index] = Value Leaves }
begin
  FnLeaves[Index] := Value;
end;

procedure TModelParameters.SetnBranches(Index: byte; Value: integer);
{ Pre: 0 <= Index < Length(FnBranches)
  Post: FnBranches[Index] = Value }
begin
  FnBranches[Index] := Value;
end;

procedure TModelParameters.SetnCurve(Index: byte; Value: real);
{ Pre: 0 <= Index < Length(FnCurve)
  Post: FnCurve[Index] = Value }
begin
  FnCurve[Index] := Value;
end;

procedure TModelParameters.SetnCurveBack(Index: byte; Value: real);
{ Pre: 0 <= Index < Length(FnCurveBack)
  Post: FnCurveBack[Index] = Value }
begin
  FnCurveBack[Index] := Value;
end;

procedure TModelParameters.SetnCurveRes(Index: byte; Value: integer);
{ Pre: 0 <= Index < Length(FnCurveRes)
  Post: FnCurveRes[Index] = Value }
begin
  FnCurveRes[Index] := Value;
end;

procedure TModelParameters.SetnCurveV(Index: byte; Value: real);
{ Pre: 0 <= Index < Length(FnCurveV)
  Post: FnCurveV[Index] = Value }
begin
  FnCurveV[Index] := Value;
end;

procedure TModelParameters.SetnDownAngle(Index: byte; Value: real);
{ Pre: 0 <= Index < Length(FnDownAngle)
  Post: FnDownAngle[Index] = Value }
begin
  FnDownAngle[Index] := Value;
end;

procedure TModelParameters.SetnDownAngleV(Index: byte; Value: real);
{ Pre: 0 <= Index < Length(FnDownAngleV)
  Post: FnDownAngleV[Index] = Value }
begin
  FnDownAngleV[Index] := Value;
end;

procedure TModelParameters.SetnLength(Index: byte; Value: real);
{ Pre: 0 <= Index < Length(FnLength)
  Post: FnLength[Index] = Value }
begin
  FnLength[Index] := Value;
end;

procedure TModelParameters.SetnLengthV(Index: byte; Value: real);
{ Pre: 0 <= Index < Length(FnLengthV)
  Post: FnLengthV[Index] = Value }
begin
  FnLengthV[Index] := Value;
end;

procedure TModelParameters.SetnRotate(Index: byte; Value: real);
{ Pre: 0 <= Index < Length(FnRotate)
  Post: FnRotate[Index] = Value }
begin
  FnRotate[Index] := Value;
end;

procedure TModelParameters.SetnRotateV(Index: byte; Value: real);
{ Pre: 0 <= Index < Length(FnRotateV)
  Post: FnRotateV[Index] = Value }
begin
  FnRotateV[Index] := Value;
end;

procedure TModelParameters.SetnSegSplits(Index: byte; Value: real);
{ Pre: 0 <= Index < Length(FnSegSplits)
  Post: FnSegSplits[Index] = Value }
begin
  FnSegSplits[Index] := Value;
end;

procedure TModelParameters.SetnSplitAngle(Index: byte; Value: real);
{ Pre: 0 <= Index < Length(FnSplitAngle)
  Post: FnSplitAngle[Index] = Value }
begin
  FnSplitAngle[Index] := Value;
end;

procedure TModelParameters.SetnSplitAngleV(Index: byte; Value: real);
{ Pre: 0 <= Index < Length(FnSplitAngleV)
  Post: FnSplitAngleV[Index] = Value }
begin
  FnSplitAngleV[Index] := Value;
end;

procedure TModelParameters.SetnTaper(Index: byte; Value: real);
{ Pre: 0 <= Index < Length(FnTaper)
  Post: FnTaper[Index] = Value }
begin
  FnTaper[Index] := Value;
end;

procedure TModelParameters.SetnVertices(Index: byte; Value: integer);
{ Pre: 0 <= Index < Length(FnVertices)
  Post: FnVertices[Index] = Value }
begin
  FnVertices[Index] := Value;
end;

function TModelParameters.Clones: TModelParameters;
{ Pre: True
  Ret: An exact copy of itself. }
var
  i: integer;
begin
  Result := TModelParameters.Create(Self.Levelers);
  Result.Shape := FShape;
  Result.BaseSize := FBaseSize;
  Result.BaseSplits := FBaseSplits;
  Result.Scale := FScale;
  Result.ScaleV := FScaleV;
  Result.ZScale := FZScale;
  Result.ZScaleV := FZScaleV;
  Result.Levelers := FLeveled; { This is the trick: Done in Create }
  Result.Ratio := FRatio;
  Result.FRatioPower := FRatioPower;
  Result.Lobes := FLobes;
  Result.LobeDepth := FLobeDepth;
  Result.Flare := FFlare;
  Result.Leaves := FLeaves;
  Result.LeafShape := FLeafShape;
  Result.LeafScale := FLeafScale;
  Result.LeafScaleX := FLeafScaleX;
  Result.LeafQuality := FLeafQuality;
  Result.LeafColor := FLeafColor;
  Result.LeafColorVariation := FLeafColorVariation;
  Result.LeafBackColor := FLeafBackColor;
  Result.LeafBackColorVariation := FLeafBackColorVariation;
  Result.AttractionUp := FAttractionUp;
  Result.PruneRatio := FPruneRatio;
  Result.PruneWidth := FPruneWidth;
  Result.PruneWidthPeak := FPruneWidthPeak;
  Result.PrunePowerLow := FPrunePowerLow;
  Result.PrunePowerHigh := FPrunePowerHigh;
  Result.Scale0 := FScale0;
  Result.ScaleV0 := FScaleV0;
  for i := 0 to Levelers - 1 do
  begin
    Result.nDownAngle[i] := FnDownAngle[i];
    Result.nDownAngleV[i] := FnDownAngleV[i];
    Result.nRotate[i] := FnRotate[i];
    Result.nRotateV[i] := FnRotateV[i];
    Result.nLength[i] := FnLength[i];
    Result.nLengthV[i] := FnLengthV[i];
    Result.nTaper[i] := FnTaper[i];
    Result.nBranches[i] := FnBranches[i];
    Result.nSegSplits[i] := FnSegSplits[i];
    Result.nSplitAngle[i] := FnSplitAngle[i];
    Result.nSplitAngleV[i] := FnSplitAngleV[i];
    Result.nCurveRes[i] := FnCurveRes[i];
    Result.nCurveBack[i] := FnCurveBack[i];
    Result.nCurve[i] := FnCurve[i];
    Result.nCurveV[i] := FnCurveV[i];
    Result.nVertices[i] := FnVertices[i];
    Result.nLeaves[i] := FnLeaves[i];
  end;
  Result.TreeSeed := FTreeSeed;
  Result.Health := FHealth;
  Result.Season := FSeason;
  Result.TreeImageFile := FTreeImageFile;
  Result.TreeShapeFile := FTreeShapeFile;
  Result.TreeBarkFile := FTreeBarkFile;
  Result.TreeColorVariation := FTreeColorVariation;
  Result.TreeColor := FTreeColor;
  Result.Distance := FDistance;
  Result.WindStrength := FWindStrength;
  Result.WindGust := FWindGust;
  Result.WindFrom := FWindFrom;
  Result.SunHeight := FSunHeight;
  Result.SunStrength := FSunStrength;
  Result.SunFrom := FSunFrom;
  Result.LeafImageFile := FLeafImageFile;
  Result.LeafShapeFile := FLeafShapeFile;
  Result.LeafTextureFile := FLeafTextureFile;
  Result.LeafLocation := FLeafLocation;
  Result.FLeafsPer := FFLeafsPer;
  Result.LeafGrouping := FLeafGrouping;

  Result.FruitPattern := FFruitPattern;
  Result.FruitScale := FFruitScale;
  Result.FruitScaleX := FFruitScaleX;
  Result.Fruits := FFruits;
  Result.FruitPer := FFruitPer;
  Result.FruitLocation := FFruitLocation;
  Result.FruitImageFile := FFruitImageFile;
  Result.FruitShapeFile := FFruitShapeFile;
  Result.FruitTextureFile := FFruitTextureFile;
  Result.FruitColorVariation := FFruitColorVariation;
  Result.FruitColor := FFruitColor;
end;

end.
